package com.tian.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tian.common.CommonResult;
import com.tian.dto.*;
import com.tian.entity.ChargeRecord;
import com.tian.entity.ChargeStationGun;
import com.tian.entity.ChargingDataRespDto;
import com.tian.entity.StationInfo;
import com.tian.enums.ChargerStatusEnum;
import com.tian.enums.PayStatusEnum;
import com.tian.enums.ResultCode;
import com.tian.influx.entity.ChargingData;
import com.tian.mapper.ChargeRecordMapper;
import com.tian.mapper.ChargeStationGunMapper;
import com.tian.mapper.ChargeStationInfoMapper;
import com.tian.mqtt.enums.MqttTopicEnum;
import com.tian.mqtt.message.ChargerStopPublishMessage;
import com.tian.mqtt.message.ChargerStopSubscribeMessage;
import com.tian.netty.executor.ChargingFlowService;
import com.tian.service.ChargeRecordService;
import com.tian.util.*;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.Future;

/**
 * {@code @description:} 充电记录
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024/2/20 20:48
 * {@code @version:} 1.0
 */
@Slf4j
@Service
public class ChargeRecordServiceImpl implements ChargeRecordService {
    @Resource
    private MqttClient client4Publish;
    @Resource
    private ChargeRecordMapper chargeRecordMapper;
    @Resource
    private ChargeStationGunMapper chargeStationGunMapper;
    @Resource
    private ChargeStationInfoMapper chargeStationInfoMapper;
    @Resource
    private RedissonClient redissonClient;
//    @Autowired
//    private InfluxdbTemplate influxDBTemplate;
    @Resource
    private ChargingFlowService chargingFlowService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommonResult<Boolean> startCharge(ChargingStartReqDto chargingStartReqDto) {
        if (StringUtil.isEmpty(chargingStartReqDto.getGunNo())) {
            log.error("gunNo参数不能为空");
            return CommonResult.failed(ResultCode.PARAMETER_EMPTY.getCode(), "gunNo参数不能为空");
        }
        ChargeStationGun chargeGun = chargeStationGunMapper.selectByGunNo(chargingStartReqDto.getGunNo());
        if (chargeGun == null) {
            log.error("接受到消息中gunNo有误，request parameter={}", chargingStartReqDto);
            return CommonResult.failed(ResultCode.PARAMETER_EMPTY.getCode(), "gunNo参数有误");
        }
        if (chargeGun.getStatus() != ChargerStatusEnum.IDLE.getChargerStatus()) {
            String byStatus = ChargerStatusEnum.getByStatus(chargeGun.getStatus());
            log.error("枪{}正在{}中，不能使用", chargeGun.getGunNo(), byStatus);
            return CommonResult.failed(ResultCode.GUN_ERROR);
        }
        boolean isExists = chargeRecordMapper.checkRecordExists(chargeGun.getId());
        if (isExists) {
            log.error("枪{}正在充电中，不能重复充电", chargeGun.getGunNo());
            return CommonResult.failed(ResultCode.GUN_USING);
        }
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        StationInfo charger = chargeStationInfoMapper.selectByPrimaryKey(chargeGun.getStationId());

        ChargeRecord chargerRecord = new ChargeRecord();
        chargerRecord.setStationGunId(chargeGun.getId());
        chargerRecord.setUserId(user.getId());
        chargerRecord.setPayStatus(PayStatusEnum.INIT.getPayStatus());
        chargerRecord.setPrice(charger.getPrice());
        chargerRecord.setStartTime(new Date());
        chargerRecord.setCreateTime(new Date());
        chargerRecord.setQuantity(BigDecimal.ZERO);
        chargerRecord.setChargeStatus(ChargerStatusEnum.CHARGING.getChargerStatus());

        chargeRecordMapper.insert(chargerRecord);

        JSONObject params = new JSONObject();
        params.put("chargerNo", chargeGun.getGunNo());
        params.put("orderId", chargerRecord.getId());

        //发送启动电桩指令
        Future<Object> sendMsgFuture = chargingFlowService.sendStarChargerMsg(params);

        try {
            if (sendMsgFuture == null || !sendMsgFuture.get().equals("success")) {
                return CommonResult.failed(ResultCode.CHARGING_START_FAILED);
            }
        } catch (Exception e) {
            log.error("发送启动电桩指令失败", e);
            return CommonResult.failed(ResultCode.CHARGING_START_FAILED);
        }
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public void doStartCharge(ChargeRecordAddReqDto chargerRecordAddReqDto) {

    }

    @Override
    public CommonResult<ChargeRecordUpdateRespDto> readyStopCharge(ChargeRecordUpdateReqDto
                                                                           chargerRecordUpdateReqDto) {
        Long id = chargerRecordUpdateReqDto.getId();
        ChargeRecord chargerRecord = chargeRecordMapper.selectByPrimaryKey(id);

        ChargeUserLoginResDto user = UserCacheUtil.getUser();

        ChargeStationGun chargeGun = chargeStationGunMapper.selectByPrimaryKey(chargerRecord.getStationGunId());

        ChargerStopPublishMessage chargerStopMessage = new ChargerStopPublishMessage();
        chargerStopMessage.setName(chargeGun.getGunName());
        chargerStopMessage.setUserId(user.getId());
        chargerStopMessage.setGunNo(chargeGun.getGunNo());
        MqttMessage message = new MqttMessage();
        message.setQos(0);
        message.setPayload(JSON.toJSONString(chargerStopMessage).getBytes());
        try {
            //发送指令  充电结，设备那边根据发过去的指令进行充电结束，再发充电结束指令 回  系统里
            client4Publish.publish(MqttTopicEnum.CHARGER_STOP_CHARGER_GUN.getTopicName(), message);
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
        return CommonResult.success();
    }

    @Override
    public void doStopCharge(ChargerStopSubscribeMessage chargerStopSubscribeMessage) {
        ChargeStationGun chargeGun = chargeStationGunMapper.selectByGunNo(chargerStopSubscribeMessage.getGunNo());

        StationInfo charger = chargeStationInfoMapper.selectByPrimaryKey(chargeGun.getStationId());

        ChargeRecord chargerRecord = chargeRecordMapper.selectByChargeGunId(chargeGun.getId());

        Date endTime = DateTimeUtil.parseDate(chargerStopSubscribeMessage.getEndTime(), DateTimeUtil.DATE_TIME_FORMAT);

        BigDecimal price = charger.getPrice();
        //如果设备端无法计算电量度数，那就使用功率乘以  (结束时间-开始时间) 分钟单位，再除以60.
        BigDecimal quantity = chargerStopSubscribeMessage.getQuantity();

        BigDecimal money = price.multiply(quantity);

        chargerRecord.setAmount(money);
        chargerRecord.setEndTime(endTime);
        chargerRecord.setQuantity(quantity);
        chargerRecord.setChargeStatus(ChargerStatusEnum.CHARGER_FINISH.getChargerStatus());
        chargeRecordMapper.updateByPrimaryKey(chargerRecord);
    }

    @Override
    public CommonResult<ChargeRecordRespDto> selectById(Long id) {
        ChargeRecord chargerRecord = chargeRecordMapper.selectByPrimaryKey(id);
        ChargeRecordRespDto chargerRecordRespDto = ChargeRecordConvert.convert4SelectById(chargerRecord);
        return CommonResult.success(chargerRecordRespDto);
    }

    @Override
    public CommonResult<ChargeRecordPageRespDto> page(ChargeRecordPageReqDto chargerRecordPageReqDto) {
        return null;
    }

    @Override
    public CommonResult<ChargeTimesCountRespDto> chargeTimesCount(String date) {
        Date queryDate = DateUtils.parse(date, DateUtils.FORMAT_DATE);
        int chargeTimesCount = chargeRecordMapper.chargeTimesCount(queryDate);
        ChargeTimesCountRespDto chargeTimesCountRespDto = new ChargeTimesCountRespDto();
        chargeTimesCountRespDto.setCount(chargeTimesCount);
        chargeTimesCountRespDto.setDate(date);
        return CommonResult.success(chargeTimesCountRespDto);
    }

    @Override
    public CommonResult<ChargeTimesCountRespDto> chargeTimesCountLasMonth() {
        Date date = new Date();
        String lastMonth = DateUtils.formatDateTime(DateUtils.add(date, Calendar.DAY_OF_MONTH, -1));
        RBucket<Integer> bucket = redissonClient.getBucket(RedisConstantPre.MONTH_COUNT_STATISTICS_CHARGE + lastMonth);
        Integer count = bucket.get();
        ChargeTimesCountRespDto chargeTimesCountRespDto = new ChargeTimesCountRespDto();
        chargeTimesCountRespDto.setDate(lastMonth);

        chargeTimesCountRespDto.setCount(count == null ? 0 : count);
        return CommonResult.success();
    }

    @Override
    public CommonResult<ChargingDataRespDto> chargingData(ChargingStartReqDto chargingStartReqDto) {

        RBucket<String> bucket = redissonClient.getBucket(RedisConstantPre.CHARGING_RECORD_PRE + chargingStartReqDto.getChargingRecordId());
        Date startTime = null;
        if (StringUtil.isBlank(bucket.get())) {
            ChargeRecord chargeRecord = chargeRecordMapper.selectByPrimaryKey(chargingStartReqDto.getChargingRecordId());
            startTime = chargeRecord.getStartTime();
            bucket.set(JSON.toJSONString(chargeRecord));
        } else {
            ChargeRecord chargeRecord = JSON.parseObject(bucket.get(), ChargeRecord.class);
            startTime = chargeRecord.getStartTime();
        }

//        QueryModel queryModel = new QueryModel();
//        Map<String, Object> map = new TreeMap<>();
//        map.put("gun_no", chargingStartReqDto.getGunNo());
//        map.put("charge_record_id", chargingStartReqDto.getChargingRecordId().toString());
//        queryModel.setMeasurement(InfluxdbUtils.getMeasurement(ChargingData.class));
//        queryModel.setMap(map);
//        queryModel.setStart(startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
//        queryModel.setEnd(LocalDateTime.now());
//        queryModel.setOrder(Order.DESC);
//        queryModel.setWhere(Op.where(queryModel) + " LIMIT 1");
//        queryModel.setWhere(Op.where(queryModel));
//        List<ChargingData> chargingDataList = influxDBTemplate.selectList(Query.build(queryModel), ChargingData.class);
//        if (chargingDataList.isEmpty()) {
//            return CommonResult.failed(ResultCode.CHARGE_DATA_NOT_EXIST);
//        }
//        ChargingData chargingData = chargingDataList.get(0);
//        ChargingDataRespDto chargingDataRespDto = new ChargingDataRespDto();
//        chargingDataRespDto.setGunNO(chargingStartReqDto.getGunNo());
//        chargingDataRespDto.setChargingNum(chargingData.getChargeNum());
//        chargingDataRespDto.setChargingNumMost();
//        return CommonResult.success(chargingDataRespDto);
        return CommonResult.success();
    }
}
